join & pivot

Aula 12, M2

Carolina Musso

Sala de Situação - UnB

Esta semana

Aula 12 - Unindo e transformando

Funções join(), pivot_longer/wider.

Aula 13 - Trabalhando com texto (strings) e datas

  • Vocês! aula 13.1 Edição com set_header_labels(), add_header_row(), set_caption() e font(). Entregar o .Rmd da tabela da aula com algumas modificações simples.

  • Pacotes stringr e lubridate

Leituras para aprofundamento

Join

Pivoting

joins (merge, linkage…)

Porque Unir bases

  • Base 1
# A tibble: 5 × 2
  date_onset hospital         
  <date>     <chr>            
1 2014-05-18 Port Hospital    
2 2014-05-21 Military Hospital
3 2014-05-22 Port Hospital    
4 2014-06-06 Port Hospital    
5 2014-06-13 Military Hospital
  • Base 2
# A tibble: 5 × 3
  Hospital          N_residentes level    
  <fct>                    <dbl> <chr>    
1 central hospital       1950280 Tertiary 
2 military hospital        40500 Secondary
3 military hospital        10000 Primary  
4 port hospital            50280 Secondary
5 central hospital         12000 Secondary

Que problemas podem aparecer?

Joins cássicos (não probabilísticos)

  • Preciso de pelo menos de uma coluna “chave” para união.

    • correspondência exata
  • Preciso Garantir

  • mesmo nome de coluna (é melhor)

  • mesma classe de coluna

  • nomes da chave que correspondam com exatidão

Voltando às bases

# A tibble: 5 × 2
  date_onset hospital         
  <date>     <chr>            
1 2014-05-18 Port Hospital    
2 2014-05-21 Military Hospital
3 2014-05-22 Port Hospital    
4 2014-06-06 Port Hospital    
5 2014-06-13 Military Hospital
# A tibble: 5 × 3
  Hospital          N_residentes level    
  <fct>                    <dbl> <chr>    
1 central hospital       1950280 Tertiary 
2 military hospital        40500 Secondary
3 military hospital        10000 Primary  
4 port hospital            50280 Secondary
5 central hospital         12000 Secondary

Primeiro problema

  • Mudar os nomes das colunas - Duas formas de fazer isso

pacote dplyr

  • rename()

  • Dá para encadear com o pipe %>%

R base

  • names()

  • deve ter aspas e também todos os nomes

Como fazer

  • Com o dplyr
ebola_mini <- ebola_mini %>% 
  rename(Inicio_sint=date_onset,
        Hospital=hospital)
  • Com o R base
names(ebola_mini) <- c("Inicio_sint", 
                     "Hospital")

Como ficou

# A tibble: 5 × 2
  Inicio_sint Hospital         
  <date>      <chr>            
1 2014-05-18  Port Hospital    
2 2014-05-21  Military Hospital
3 2014-05-22  Port Hospital    
4 2014-06-06  Port Hospital    
5 2014-06-13  Military Hospital
# A tibble: 5 × 3
  Hospital          N_residentes level    
  <fct>                    <dbl> <chr>    
1 central hospital       1950280 Tertiary 
2 military hospital        40500 Secondary
3 military hospital        10000 Primary  
4 port hospital            50280 Secondary
5 central hospital         12000 Secondary

Segundo problema

  • As colunas “chave” devem ser do mesmo tipo.

  • Vemos que nesse caso, uma é fator e a outra um caractere.

    • Devemos transformar uma delas

começamos com um mutate()

  • função as.?

    • as.numeric
    • as.character

. . .

hosp_info <- hosp_info %>% 
  mutate(Hospital=as.character(Hospital))

Como ficou

# A tibble: 5 × 2
  Inicio_sint Hospital         
  <date>      <chr>            
1 2014-05-18  Port Hospital    
2 2014-05-21  Military Hospital
3 2014-05-22  Port Hospital    
4 2014-06-06  Port Hospital    
5 2014-06-13  Military Hospital
# A tibble: 5 × 3
  Hospital          N_residentes level    
  <chr>                    <dbl> <chr>    
1 central hospital       1950280 Tertiary 
2 military hospital        40500 Secondary
3 military hospital        10000 Primary  
4 port hospital            50280 Secondary
5 central hospital         12000 Secondary

Terceiro problema

  • Os nomes não estão escritos da mesma forma

  • Funções úteis

    • toupper() ou str_to_upper()
    • tolower() ou str_to_lower()
    • veremos outras possibilidades na próxima aula
ebola_mini <- ebola_mini %>% 
  mutate(Hospital=str_to_lower(Hospital))
  • Uma boa prática é sempre padronizar os textos de todas as bases que for trabalhar antes de começar os joins.

Como ficou

# A tibble: 5 × 2
  Inicio_sint Hospital         
  <date>      <chr>            
1 2014-05-18  port hospital    
2 2014-05-21  military hospital
3 2014-05-22  port hospital    
4 2014-06-06  port hospital    
5 2014-06-13  military hospital
# A tibble: 5 × 3
  Hospital          N_residentes level    
  <chr>                    <dbl> <chr>    
1 central hospital       1950280 Tertiary 
2 military hospital        40500 Secondary
3 military hospital        10000 Primary  
4 port hospital            50280 Secondary
5 central hospital         12000 Secondary

Agora sim!

Podemos seguir com o join!

  • Repare no nome da função usada.
ebola_hosp_info  <-  left_join(ebola_mini, hosp_info)
# A tibble: 4 × 4
  Inicio_sint Hospital          N_residentes level    
  <date>      <chr>                    <dbl> <chr>    
1 2014-05-18  port hospital            50280 Secondary
2 2014-05-21  military hospital        40500 Secondary
3 2014-05-21  military hospital        10000 Primary  
4 2014-05-22  port hospital            50280 Secondary

Existem vários joins!

  • left_join()

  • right_join()

  • inner_join()

  • full_join()

  • semi_join()

  • anti_join()

  • E tem mais coisa na nova versão do dplyr!

  • E agora, qual usar?

left_join()

  • Mantém todas as linhas do data frame da esquerda, exclui as que não batem do data frame da direita.
base_unida <- left_join(a,b)

right_join()

  • Mantém todas as linhas do data frame da direita, exclui as que não batem do data frame da esquerda.
base_unida <- right_join(a,b)

full_join()

  • Mantém todas as linhas de ambas as bases -> completa com NA
base_unida <- full_join(a,b)

inner_join()

  • Mantém somente as linhas que há em ambas
base_unida <- inner_join(a,b)

semi_join()

  • Não faz join! -> filtra a base da esquerda de acordo com o que também tem na da direita
base_unida <- semi_join(a,b)

anti_join()

  • Não é exatamente um join! -> na verdade filtra a base da esquerda de acordo com o que não tem na da direita
base_unida <- anti_join(a,b)

Pivoting

Messy data

“Tidy datasets are all alike, but every messy dataset is messy in its own way.” —- Hadley Wickham

“Base de dados arrumadas são todas iguais, mas bases desorganizadas, são desorganizadas em sua própria maneira”

Pacote tidy

  • Deixar o data frame no formato ideal.

Formato largo (wide)

  • É bom pra tabelas, mas não é bom pra para o ggplot…

    • vamos transformar para longo

Formato longo (long)

  • É bom para o ggplot, mas não para apresentar em tabela!

    • vamos transformar para wide

Wide X Long: aplicações

  • Tomemos esse gráfico
ggplot(dado_malaria ) +
  geom_col(aes(x = data_date, y = Total), width = 1)

Vamos supor que eu queria colorir segundo a faixa-etária.

head(dado_malaria)
  location_name  data_date faixa_0_04 faixa_5_14 faixa_15_mais Total
1    Facility 1 2020-08-11         11         12            23    46
2    Facility 1 2020-08-10         11          4             5    20
3    Facility 1 2020-08-09         18          4            84   106
4    Facility 1 2020-08-04         16          7            20    43
5    Facility 1 2020-08-03         12          9            15    36
6    Facility 1 2020-08-02         14         13            12    39
  • Qual o problema?

Necessário primeiro transformar para formato longo

dado_malaria_longo <- dado_malaria  %>% 
  pivot_longer(
    cols = c(`faixa_0_04`, `faixa_5_14`, `faixa_15_mais`)
  )
# Usar a função auxiliar starts_with
dado_malaria_longo <-dado_malaria %>% 
  pivot_longer(
    cols = starts_with("faixa_")
  )

O que mudou

  • Quais novas colunas apareceram no banco? E quais sumiram?
head(dado_malaria_longo)
# A tibble: 6 × 5
  location_name data_date  Total name          value
  <chr>         <date>     <int> <chr>         <int>
1 Facility 1    2020-08-11    46 faixa_0_04       11
2 Facility 1    2020-08-11    46 faixa_5_14       12
3 Facility 1    2020-08-11    46 faixa_15_mais    23
4 Facility 1    2020-08-10    20 faixa_0_04       11
5 Facility 1    2020-08-10    20 faixa_5_14        4
6 Facility 1    2020-08-10    20 faixa_15_mais     5
  • As colunas originais desapareceram, e foram comprimidas em duas colunas chamadas “names” e “values”.

Ainda outra opção

  • Podemos ainda especificar o nome das novas colunas que surgião no banco
dado_malaria_longo <- 
  dado_malaria %>% 
  pivot_longer(
    cols = starts_with("faixa_"),
    names_to = "Faixa-etária",
    values_to = "Contagens"
  )

Agora ao gráfico!

  • Agora podemos fazer o gráfico como queríamos, colorindo as barras segundo a faixa-etária
ggplot(data = dado_malaria_longo) +
  geom_col(
    mapping = aes(x = data_date, y = Contagens, fill = `Faixa-etária`)
  )

O caso oposto

  • Outra base

  • Faixa-etária x Sexo

ggplot(dado_ebola) +
  geom_col(aes(x = age_cat, y = n, fill = gender))

head(dado_ebola)
  age_cat gender   n
1     0-4      f 640
2     0-4      m 416
3     0-4   <NA>  39
4     5-9      f 641
5     5-9      m 412
6     5-9   <NA>  42
  • Agora está bom para um gráfico mas está muito comprida para fazer uma tabela, não é mesmo?

Transformando o longo em largo

dado_ebola_largo <- 
  dado_ebola %>% 
  pivot_wider(
    id_cols = age_cat,
    names_from = gender,
    values_from = n
  )
head(dado_ebola_largo )
# A tibble: 6 × 4
  age_cat     f     m  `NA`
  <fct>   <int> <int> <int>
1 0-4       640   416    39
2 5-9       641   412    42
3 10-14     518   383    40
4 15-19     359   364    20
5 20-29     468   575    30
6 30-49     179   557    18

Até a próxima aula!